﻿using Sidvall.Serialization;
using Sidvall.UI.Messaging;

namespace Sidvall.UI.ViewModels
{
    public abstract class ControlViewModelBase : NavigatingObjectBase, IBindingContext
    {
        #region Public Members

        public event System.EventHandler<BusyChangedEventArgs> IsBusyChanged;

        #region IsBusy

        private bool _IsBusy;
        public bool IsBusy
        {
            get
            {
                return _IsBusy;
            }
            set
            {
                SetIsBusy(value, null, null);
            }
        }

        #endregion
        #region IsBusyMessage

        private string _IsBusyMessage;
        public string IsBusyMessage
        {
            get
            {
                return _IsBusyMessage;
            }
            set
            {
                if (_IsBusyMessage == value)
                    return;
                _IsBusyMessage = value;
                RaisePropertyChanged(nameof(IsBusyMessage));
            }
        }

        #endregion
        #region IsBusyScope

        private string _IsBusyScope;
        public string IsBusyScope
        {
            get
            {
                return _IsBusyScope;
            }
            set
            {
                if (_IsBusyScope == value)
                    return;
                _IsBusyScope = value;
                RaisePropertyChanged(nameof(IsBusyScope));
            }
        }

        #endregion
        #region ViewModelControls

        private volatile ViewModelControlCollection _ViewModelControls;
        public ViewModelControlCollection ViewModelControls
        {
            get
            {
                if (_ViewModelControls == null)
                {
                    lock (_Mutex)
                    {
                        if (_ViewModelControls == null)
                        {
                            var items = new ViewModelControlCollection();
                            items.IsBusyChanged += OnViewModelControlsIsBusyChanged;
                            _ViewModelControls = items;
                        }
                    }
                }
                return _ViewModelControls;
            }
        }

        #endregion

        // Protected
        #region OnIsBusyChanged

        protected virtual void OnIsBusyChanged()
        {
        }
        protected virtual void OnIsBusyChanged(bool isBusy, string message, string scope)
        {
            OnIsBusyChanged();
            OnIsBusyChanged(this, new BusyChangedEventArgs(this.IsBusy, message, scope));
        }
        protected void OnIsBusyChanged(object sender, BusyChangedEventArgs args)
        {
            if (this.IsBusyChanged != null)
                this.IsBusyChanged.Invoke(this, args);
        }

        #endregion
        #region OnViewModelEvent

        protected virtual void OnViewModelEvent(ViewModelMessage message)
        {
            EventManager.Publish(message);
        }

        #endregion
        #region OnViewModelControlsIsBusyChanged

        protected virtual void OnViewModelControlsIsBusyChanged(object sender, BusyChangedEventArgs e)
        {
            OnIsBusyChanged(sender, e);
        }

        #endregion
        #region UnloadViewModel

        protected override void UnloadViewModel()
        {
            if (_ViewModelControls != null)
            {
                _ViewModelControls.IsBusyChanged -= OnViewModelControlsIsBusyChanged;
                _ViewModelControls.Clear();
                _ViewModelControls = null;
            }
            base.UnloadViewModel();
        }

        #endregion
        #region SetIsBusy

        protected void SetIsBusy(bool isBusy, string message, string scope)
        {
            if (isBusy)
            {
                if (!_IsBusy)
                {
                    _IsBusy = true;
                    RaisePropertyChanged(nameof(IsBusy));
                    this.IsBusyMessage = message;
                    this.IsBusyScope = scope;
                    OnIsBusyChanged(isBusy, message, scope);
                }
            }
            else if (_IsBusy)
            {
                if (this.IsBusyScope.Equals(scope, true, System.StringComparison.OrdinalIgnoreCase))
                {
                    _IsBusy = false;
                    RaisePropertyChanged(nameof(IsBusy));
                    this.IsBusyMessage = null;
                    this.IsBusyScope = null;
                    OnIsBusyChanged(isBusy, message, scope);
                }
            }
        }

        #endregion

        #region IBusyProvider Members

        void Sidvall.Data.IBusyProvider.SetIsBusy(bool isBusy, string message, string scope)
        {
            SetIsBusy(isBusy, message, scope);
        }

        #endregion

        #endregion
        #region Private Members

        private readonly object _Mutex = new object();

        #endregion
        #region Constructors

        protected ControlViewModelBase()
        {
        }

        #endregion
    }
}
